package input;

import input.list.ListNodeConverter;

import java.lang.reflect.Executable;
import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

public class ParameterResolver {

    private final Type[] paramTypes;
    private List<ParameterConverter> converters;
    private static final Map<String, ParameterConverter> converterMap = new HashMap<>();

    static {
        converterMap.put("int", TestUtil::stringToInteger);
        converterMap.put("int[]", TestUtil::stringToIntegerArray);
        converterMap.put("int[][]", TestUtil::stringToInteger2dArray);
        converterMap.put("java.util.List<java.lang.Integer>", TestUtil::stringToIntegerArrayList);
        converterMap.put("java.util.List<java.util.List<java.lang.Integer>>", TestUtil::stringToInt2dList);
        converterMap.put("java.lang.String", TestUtil::stringToString);
        converterMap.put("java.lang.String[]", TestUtil::getStringArr);
        converterMap.put("input.tree.binary.TreeNode", TestUtil::stringToTreeNode);
        converterMap.put("input.list.ListNode", new ListNodeConverter());
    }

    public ParameterResolver(Executable executable) {
        this.paramTypes = executable.getGenericParameterTypes();
    }


    public Object[] resolve(List<String> originalParams) {
        List<ParameterConverter> converters = prepareConverters();
        Iterator<ParameterConverter> it = converters.iterator();
        return originalParams.stream()
                .map(e -> it.next().convert(e)).toArray();
    }

    private List<ParameterConverter> prepareConverters() {
        if (converters != null) {
            return converters;
        }
        converters = Arrays.stream(paramTypes)
                .map(this::getConverter)
                .collect(Collectors.toList());
        return converters;
    }

    private ParameterConverter getConverter(Type type) {
        return converterMap.get(type.getTypeName());
    }

}
